package yhao.infra.common.logger;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import ch.qos.logback.core.util.FileSize;
import org.apache.commons.lang3.StringUtils;
import yhao.infra.common.util.CommonDateUtil;

import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author yoara
 * <p> Created on 2021/9/22 </p>
 */
public class CommonLoggerFactory {
    public static final String USER_AGENT_NAME = "user-agent";
    public static final String MSG_FORMAT = "%msg%n";
    public static final String LOG_DEFAULT = "-";

    /**
     * 输出滚动日志模式
     * 默认级别为INFO
     * 默认大小50M
     */
    public static org.slf4j.Logger makeRollingFileLogger(LoggerParam param){
        Logger logger = new LoggerContext().getLogger(param.getClazz());
        final LoggerContext loggerContext = logger.getLoggerContext();
        loggerContext.start();
        String filePath = param.getBaseDir() + "/" + param.getFileName();
        RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<ILoggingEvent>(){{
            setContext(loggerContext);
            setFile(filePath + ".log");

            PatternLayoutEncoder encoder = new PatternLayoutEncoder(){{
                setContext(loggerContext);
                setPattern(param.getFormat());
            }};
            encoder.start();

            TimeBasedRollingPolicy timeBasedRollingPolicy = new TimeBasedRollingPolicy(){{
                setContext(loggerContext);
                setFileNamePattern(filePath + "-%d{yyyyMMdd}.%i.log");

                setTimeBasedFileNamingAndTriggeringPolicy(new SizeAndTimeBasedFNATP() {{
                    setContext(loggerContext);
                    setMaxFileSize(FileSize.valueOf(param.getSize()));
                }});
            }};
            timeBasedRollingPolicy.setParent(this);
            timeBasedRollingPolicy.start();

            setRollingPolicy(timeBasedRollingPolicy);
            setEncoder(encoder);
        }};
        appender.start();

        logger.setAdditive(false);
        logger.setLevel(param.getLevel());
        logger.addAppender(appender);
        return logger;
    }

    public static String getValue(String value) {
        return StringUtils.isBlank(value) ? LOG_DEFAULT : value;
    }

    public static String getValue(Long value) {
        return value == null ? LOG_DEFAULT : value.toString();
    }

    public static String getValue(Boolean value) {
        return value == null ? LOG_DEFAULT : value.toString();
    }

    public static String getValue(Date value) {
        return value == null ? LOG_DEFAULT : CommonDateUtil.formatDateToyyyy_MM_dd_HH_mm_ss(value);
    }

    static Pattern p = Pattern.compile("\t|\r|\n|#");
    public static String replaceUnNeed(String str) {
        if (str!=null) {
            Matcher m = p.matcher(str);
            String dest = m.replaceAll("");
            return dest;
        }
        return LOG_DEFAULT;
    }

    /**
     * 当前应用是否部署在windows下
     */
    public static boolean isSystemWindows() {
        return System.getProperty("os.name").toLowerCase().startsWith("win");
    }


    public static class LoggerParam {
        /** 文件大小 {@link ch.qos.logback.core.util.FileSize} **/
        private String size = "50000kb";
        /** 日志输出格式 **/
        private String format = "%d{yyyy-MM-dd HH:mm:ss}  %m%n";
        /** 输出级别 **/
        private Level level = Level.INFO;
        /** 日志路径 **/
        private String baseDir;
        /** 生成日志路径 **/
        private String fileName;
        /** 引用类相关 **/
        private Class clazz;

        public LoggerParam(String baseDir, String fileName, Class clazz) {
            this.baseDir = baseDir;
            this.fileName = fileName;
            this.clazz = clazz;
        }

        public String getSize() {
            return size;
        }

        public LoggerParam setSize(String size) {
            this.size = size;
            return this;
        }

        public String getFormat() {
            return format;
        }

        public LoggerParam setFormat(String format) {
            this.format = format;
            return this;
        }

        public String getBaseDir() {
            return baseDir;
        }

        public LoggerParam setBaseDir(String baseDir) {
            this.baseDir = baseDir;
            return this;
        }

        public String getFileName() {
            return fileName;
        }

        public LoggerParam setFileName(String fileName) {
            this.fileName = fileName;
            return this;
        }

        public Class getClazz() {
            return clazz;
        }

        public LoggerParam setClazz(Class clazz) {
            this.clazz = clazz;
            return this;
        }

        public Level getLevel() {
            return level;
        }

        public LoggerParam setLevel(Level level) {
            this.level = level;
            return this;
        }
    }
}
